﻿using System;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using USNetFramework.PacketBuilder;
using USNetFramework.Network;
using USNetFramework.RPC;
using Google.Protobuf.Examples.AddressBook;
using Google.Protobuf;
using USNetFramework.Utils;
using SocketProto = US.Proto.Socket;
using LoginProto = US.Proto.Login;
using Skynet = Crypt.Skynet;
using Sproto;
using NetFramework;

namespace Test
{
    public class TestLogin : IClientKernel, ISocketListener
    {
        private byte[] m_cbClientKey = Skynet.Crypt.RandomKey();
        private byte[] m_cbServerKey = null;
        private byte[] m_cbChallage = null;
        private byte[] m_cbSecret = null;
        private PacketBuilder pbBuilder = null;
        private NetSocket clientSocket = null;

        // 派发线程
        private Thread m_subThread;


        public TestLogin()
        {
            this.Init();

            DateTime dt = DateTime.UtcNow;
            DateTimeOffset dto = DateTimeOffset.UtcNow;

            this.TestRpc();
            m_subThread = new Thread(SubMain);
            //m_subThread.Start();
        }

        private void SubMain()
        {
            while (true)
            {
                Thread.Sleep(500);
                TestSendHeartBeat(clientSocket);
            }
        }

        public void TestRpc()
        {
            //LoginProto.login_request lreq = new LoginProto.login_request();
            //lreq.Request = new LoginProto.C2S_Login_Handshake();
            //lreq.Request.Clientkey = "我测测看对不对";
            //lreq.Response = new LoginProto.S2C_Login_Handshake();

            //NetPacket p = new NetPacket(1, 1);
            //p.DataBuffer = lreq.ToByteArray();

            //RpcManager.Instance.SendRpc(p, pack => {

                //NetPacket p1 = pbBuilder.Pack<LoginProto.login_request>(1, 1, lreq);
                //LoginProto.login_request msg = pbBuilder.Unpack<LoginProto.login_request>(p1);

                //lreq = LoginProto.login_request.Parser.ParseFrom(pack.DataBuffer);
            //});


            //p.RequestType = EnumRequestType.Response;
            //RpcManager.Instance.Received(p, clientSocket);
        }

        private void Init()
        {

            if (null == pbBuilder)
            {
                var builder = new NetPacketBuilder();
                builder.Init();
                pbBuilder = builder;
            }

            if (null == clientSocket && null != pbBuilder)
            {
                clientSocket = new NetSocket(pbBuilder);
            }
            Debug.Assert((null != pbBuilder && null != clientSocket), "init failed");

            clientSocket.Regiester(this);
            clientSocket.Connect("localhost", 8001);
        }

        public void OnUpdate()
        {
            clientSocket.OnUpdate();
        }

        private void send_buffer(NetSocket socket, byte[] inBuffer)
        {
            byte[] buffer = new byte[inBuffer.Length + 2];
            NetStream ns = new NetStream(buffer, true);
            ns.WriteBuffer(inBuffer);
            ns.Close();
            socket.SyncSendBytes(buffer);
        }

        public bool OnHandleMessage(NetSocket socket, NetPacket packet)
        {
            Console.Write("Recv Msg \n");

            // clientSocket.Close();
            // Thread.Sleep(10);
            // clientSocket.Connect("localhost", 8001);
            // TestSendHeartBeat(socket);

            //SPNetPacket spPack = (SPNetPacket)packet;
            //SprotoObject spObj = spPack.Response;

            //long i = (int)spObj["cnt"];
            //SprotoHelper.Assert(spObj["cnt"] == 2);


            //switch (packet.ProtoType)
            //{
            //    case 0:
            //        Console.Write("Socket Packet \n");
            //        OnHandleSocketMessage(socket, packet);
            //        break;
            //    case 1:
            //        Console.Write("Login Packet \n");
            //        OnHandleLoginMessage(socket, packet);
            //        break;
            //    default:
            //        Console.Write("Drop Packet \n");
            //        break;
            //}
            return true;
        }


        public void OnHandleSocketMessage(NetSocket socket, NetPacket packet)
        {
            switch (packet.ProtoID)
            {
                case 1:
                    break;
                default:
                    break;
            }
        }

        public void OnHandleLoginMessage(NetSocket socket, NetPacket packet)
        {
            switch (packet.ProtoID)
            {
                case 1:
                    break;
                default:
                    break;
            }
        }

        public void OnSocketConnected(NetSocket socket)
        {
            Console.Write("Connet Scuess");
            m_subThread.Start();
            TestSendHeartBeat(socket);
        }

        public void TestSendHeartBeat(NetSocket socket)
        {
            SPNetMsg msg = new SPNetMsg();
            msg.ProtoType = 0;
            msg.ProtoName = "heartbeat";
            msg.Data = new SprotoObject("heartbeat");
            msg.Data["client_info"] = new SprotoObject("client_info");
            msg.Data["client_info"]["client_time"] = GetCurrentTime();

            socket.SendData(msg, (retPacket) =>
            {
                // TODO 错误码处理
                SPNetPacket sp = (SPNetPacket)retPacket;
                if (null != sp.Response)
                    TestRecvHeartBeat(sp.Response);
            });
        }

        public void TestRecvHeartBeat(SprotoObject obj)
        {
            long serverTime = obj["server_info"]["server_time"];

            long sendTime = obj["client_info"]["client_time"];
            long recvTime = GetCurrentTime();
            short lag = (short)(recvTime - sendTime);

            Log.WriteInfo("client time is {0}", recvTime);
            Log.WriteInfo("server time is {0}", serverTime);
            Log.WriteInfo("server lag is {0}", lag / 2);
        }

        public long GetCurrentTime()
        {
            return (long)(DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000;
        }

        public void OnSocketConnectTimout(NetSocket socket)
        {
            // throw new NotImplementedException();
        }

        public void OnSocketDisconnected(NetSocket socket)
        {
            // throw new NotImplementedException();
        }
    }
}
